#include "mySocket.h"

char flag; 
int sockfd;
int listenfd;
struct sockaddr_in sockAddr, listenAddr;
char buf[BUF_SIZE];
char myUID[LEN];
struct msgHead msgh;

void writeMsg(int fd, msgHead *HeadMsg, char *buf){
    if ((write(fd, HeadMsg, sizeof(msgHead))) < 0){
            perror("write error");
            exit(0);
    }
    if ((write(fd,buf,HeadMsg->length)) < 0){
            perror("write error");
            exit(0);
        }
}

void readMsg(int fd, msgHead *HeadMsg, char *buf){
    int n;
    if ((n = read(fd,HeadMsg,sizeof(msgHead))) < 0){
		perror("read headmassage error");
		exit(0);
	}
    if ((n = read(fd,buf,HeadMsg->length)) < 0){
        perror("read error");
        exit(0);
    }
}

int init(int port, char *IP, SAI *addr){
    int s;
    if ((s = socket(AF_INET,SOCK_STREAM,0)) < 0){
            perror("socket error");
            exit(0);
        }
    
    bzero(addr,sizeof(sockaddr));
    addr->sin_family = AF_INET;
    addr->sin_port = htons(port);
    
    if ((inet_pton(AF_INET,IP, &(addr->sin_addr))) < 0){
        perror("inet_pton error");
        exit(0);
    }
    
    if((connect(s,(SA *)addr,sizeof(SA))) < 0){
            perror("connect error");
            exit(0);
    }
    return s;
}

void tellMessage(char *uID)
{
	msgh.cmd = P2P_REQUST;
	sprintf(buf, "%s %s", myUID, uID);
	msgh.length = strlen(buf) + 1;
	writeMsg(sockfd, &msgh, buf);
}

void sendMessage(char *uID, char *msg)
{
	sprintf(buf, "%s %s %s", myUID, uID, msg);
    int fd = getFd(uID);
    if (fd < 0)
    {
        msgh.cmd = P2P_TRANS_MSG;
        fd = -fd;
    }
    else
        msgh.cmd = P2P_MASSAGE;
    msgh.length = strlen(buf) + 1;
    writeMsg(fd, &msgh, buf);
}

void *p2pFunc(void *arg)
{
    int fd = *(int *)arg;
    int n;
    int filefd;
    char filename[LEN];
    msgHead msgh;
    char buf[BUF_SIZE];
    char UID[LEN], pUID[LEN];
    char ip[LEN];
    int connfd;
    SAI addr;
    pthread_t ptid;
    
    while (1)
    {
        readMsg(fd, &msgh, buf);
        if (msgh.cmd == HEART_BEAT_ACK);
//            puts("got heart beat!");
        //else if (msgh.cmd == ONLINE_LIST_ACK)
            //puts(buf);
        else if (msgh.cmd == P2P_RESPONSE)
        {
            if (msgh.error == 0)
            {
                //puts(buf);
                sscanf(buf, "%s %s", UID, ip);
                connfd = init(CLEN_PORT, ip, &addr);
                addFd(connfd, UID);
                pthread_create(&ptid, 0, p2pFunc, (void *) &connfd);
                msgh.cmd = P2P_CONNECT;
                sprintf(buf, "%s %s", UID, myUID);
                msgh.length = strlen(buf) + 1;
                writeMsg(connfd, &msgh, buf);
                
//                addMessage(ip, 1);
            }
            //else if (msgh.error == 1)
                //puts(buf);
            else if (msgh.error == 2)
            {
                //puts(buf);
                sscanf(buf, "%s%s%s", UID, ip, pUID);
                connfd = getFd(UID);
                if (connfd == -1)
                {
                    connfd = init(CLEN_PORT, ip, &addr);
                    addFd(connfd, UID);
                    pthread_create(&ptid, 0, p2pFunc, (void *) &connfd);
//					init_wins(UID);
                }
                addFd(-connfd, pUID);
                msgh.cmd = P2P_TRANS_CON;
                sprintf(buf, "%s %s", pUID, myUID);
                msgh.length = strlen(buf) + 1;
                writeMsg(connfd, &msgh, buf);
            }
        }
        else if (msgh.cmd == P2P_CONNECT)
        {
            sscanf(buf, "%s %s", UID, pUID);
            addFd(fd, pUID);

            init_wins(pUID);
        }
        else if (msgh.cmd == P2P_MASSAGE)
			addMessage(buf, 0);
            //puts(buf);
        else if (msgh.cmd == P2P_TRANS_CON)
        {
            sscanf(buf, "%s%s", UID, pUID);
            connfd = getFd(pUID);
            if (connfd == -1)
                addFd(fd, pUID);
            connfd = getFd(UID);
            if (connfd != -1)
            {
                msgh.cmd = P2P_TRANS_CON_ACK;
                sprintf(buf, "tell %s succuss!", UID);
                msgh.length = strlen(buf) + 1;
                writeMsg(fd, &msgh, buf);
                sprintf(buf, "tell %s succuss!", pUID);
                msgh.length = strlen(buf) + 1;
                writeMsg(connfd, &msgh, buf);
            }
        }
        //else if (msgh.cmd == P2P_TRANS_CON_ACK)
            //puts(buf);
        else if (msgh.cmd == P2P_TRANS_MSG)
        {
            sscanf(buf, "%s%s", UID, pUID);
            connfd = getFd(pUID);
            msgh.cmd = P2P_MASSAGE;
            msgh.length = strlen(buf) + 1;
            writeMsg(connfd , &msgh, buf);
        }
        else if (msgh.cmd == P2P_FILE)
        {
            sscanf(buf, "%s%s%s", UID, pUID, filename);
            filefd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
            while (1)
            {
                readMsg(fd, &msgh, buf);
                if (msgh.error == maxInt)
                    break;
                write(filefd, buf, msgh.length);
            }
            close(filefd);
            printf("get file %s\n OK!", filename);
        }
        else if (msgh.cmd == P2P_TRANS_FILE)
        {
            sscanf(buf, "%s%s", UID, pUID);
            connfd = getFd(pUID);
            msgh.cmd = P2P_FILE;
            writeMsg(connfd, &msgh, buf);
            while (1)
            {
                readMsg(fd, &msgh, buf);
                if (msgh.error == maxInt)
                    break;
                writeMsg(connfd, &msgh, buf);
            }
            writeMsg(connfd, &msgh, buf);
        }
        else if (msgh.cmd == FRIEND_CTL_ACK)
            puts(buf);
        else if (msgh.cmd == LOGOUT)
        {
            printf("Good Bye\n");
            close(fd);
        }
    }
}

void *Listen(void *arg)
{
    int n, connfd, on;
    SAI remoteAddr;
    socklen_t clilen = sizeof(SA);
    pthread_t ptid;
    
    bzero(&listenAddr, sizeof(SA));
    listenAddr.sin_family = AF_INET;
    listenAddr.sin_port = htons(CLEN_PORT);
    listenAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    
    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
    if (listenfd < 0)
        err_sys("create socket error");
    if (bind(listenfd, (SA *) &listenAddr, sizeof(SA)) < 0)
        err_sys("bind error");
    if (listen(listenfd, 10) < 0)
        err_sys("listen error");
    
    while (1)
    {
        connfd = accept(listenfd, (SA *) &remoteAddr, &clilen);
        pthread_create(&ptid, 0, p2pFunc, (void *) &connfd);
    }
}

void err_sys(const char *s)
{
    perror(s);
    exit(1);
}
